package com.example.loginproject.view.views

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
import android.graphics.Rect
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import com.example.loginproject.R
import com.example.loginproject.models.DotModel
import com.example.loginproject.models.DotState
import com.example.loginproject.tool.MyLog
import com.example.loginproject.tool.dp2px

/**
 * 如何记录密码
 * 如何知道选中了
 */
class UnlockView(context: Context, attrs: AttributeSet?): View(context, attrs) {
    private var mRadius = dp2px(40)
    private var mCenterDotRadius = 0f
    private var mSpace = dp2px(40)
    private var mStart_cx = 0f  //第一个点的起始点坐标
    private var mStart_cy = 0f
    private val mDotPaint:Paint by lazy {
        Paint().apply {
            isAntiAlias = true
            color = resources.getColor(R.color.dot_bg_color,null)
            style = Paint.Style.FILL
        }
    }
    private val mCenterDotPaint:Paint by lazy {
        Paint().apply {
            isAntiAlias = true
            color = Color.WHITE
            style = Paint.Style.FILL
        }
    }
    private val mDotSelectPaint:Paint by lazy {
        Paint().apply {
            isAntiAlias = true
            color = resources.getColor(R.color.light_blue,null)
            style = Paint.Style.STROKE
            strokeWidth = dp2px(2).toFloat()
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        var mWidth = 0
        var mHeight = 0

        //确定宽度
        val widthMode = MeasureSpec.getMode(widthMeasureSpec)
        val widthSize = MeasureSpec.getSize(widthMeasureSpec)
        mWidth = when(widthMode){
            MeasureSpec.EXACTLY -> widthSize
            else -> 6*mRadius + 4*mSpace
        }

        //确定宽度
        val heightMode = MeasureSpec.getMode(heightMeasureSpec)
        val heightSize = MeasureSpec.getSize(heightMeasureSpec)
        mHeight = when(heightMode) {
            MeasureSpec.EXACTLY -> heightSize
            else -> 6 * mRadius + 4 * mSpace
        }
        setMeasuredDimension(mWidth,mHeight)
    }
    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        //计算半径 以height和width最小的正方形来计算  (min-4*space)/6
        mRadius = (Math.min(height,width) - 4*mSpace)/6
        mCenterDotRadius = mRadius.toFloat() / 6

        //确定起始点的中心点cx cy
        mStart_cx = (width - squareSize())/2 + mSpace + mRadius.toFloat()
        mStart_cy = (height - squareSize())/2 + mSpace +mRadius.toFloat()
    }
    override fun onDraw(canvas: Canvas) {
        drawLine(canvas)
        drawNineDot(canvas)
    }
    /**绘制9个圆点*/
    private var mDotModels = arrayListOf<DotModel>() //保存9个点
    private fun drawNineDot(canvas: Canvas?){
        var index = 1
        for (i in 0 until 3) //控制行数
            for (j in 0 until 3){ //列数
                val cx = mStart_cx + j*(2*mRadius+mSpace)
                val cy = mStart_cy + i*(2*mRadius+mSpace)
                canvas?.drawCircle(cx,cy,mRadius.toFloat(),mDotPaint)

                if (index > mDotModels.size) {
                    //第一次绘制9个点 加到数组中
                    //封装圆点的模型数据
                    mDotModels.add(DotModel(index, cx, cy, mRadius.toFloat()))
                }else{
                    //已经绘制过了，这里要判断状态
                    when (mDotModels[index-1].state) {
                        DotState.Selected ->{
                           mCenterDotPaint.color = resources.getColor(R.color.light_blue,null)
                            canvas?.drawCircle(cx, cy, mCenterDotRadius, mCenterDotPaint)

                            mDotSelectPaint.color = resources.getColor(R.color.light_blue,null)
                            canvas?.drawCircle(cx, cy, mRadius.toFloat(), mDotSelectPaint)
                        }
                        DotState.Error -> {
                            //错误状态 改变画笔的颜色为红色
                            mDotSelectPaint.color = resources.getColor(R.color.red,null)
                            canvas?.drawCircle(cx, cy, mRadius.toFloat(), mDotSelectPaint)

                            mCenterDotPaint.color = resources.getColor(R.color.red,null)
                            canvas?.drawCircle(cx, cy, mCenterDotRadius, mCenterDotPaint)
                        }
                        else -> {}
                    }
                }
               index++
            }
    }
    /**画线 path*/
    private var mPath = Path()
    private val mLinePaint : Paint by lazy {
        Paint().apply {
            color = resources.getColor(R.color.light_blue,null)
            strokeWidth = dp2px(2).toFloat()
            style = Paint.Style.STROKE
        }
    }
    private var lastSelectedDotModel: DotModel? = null //记录上一个点的model
    private val mSelectedLines = arrayListOf<Int>() //保存已经点亮的线的数值
    private val mMoveLinePath = Path()  //移动的线的路劲
    private val mPasswordBuilder = StringBuilder() //记录划过的轨迹
    private var mCallback:((UnlockView,String)->Unit)? = null //回调数据
    private var mBackupPath:Path? = null    //备份连接线的路径
    private var mBackupModels: ArrayList<DotModel>? = null //备份圆点的model
    private fun drawLine(canvas: Canvas?){
        if(mPath.isEmpty)return
        canvas?.drawPath(mPath, mLinePaint)//绘制圆点之间的连接线

        if (mMoveLinePath.isEmpty)return
        canvas?.drawPath(mMoveLinePath,mLinePaint) //绘制移动式跟着手移动的线
    }
    /**触摸事件*/
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        when(event?.action){
            MotionEvent.ACTION_DOWN -> {touchBegin(event.x,event.y)}
            MotionEvent.ACTION_MOVE -> {touchBegin(event.x,event.y)}
            MotionEvent.ACTION_UP -> { touchEnd()}
        }
        return true
    }
    private fun touchBegin(x:Float,y:Float){
        if (!canTouch) return  //禁止触摸屏幕之后的事情

        val dot = isInDot(x, y)
        if (dot != null){//在某个圆点内部
            //判断这个点是不是第一个点
            if (lastSelectedDotModel == null){
                //记录当前点
                lastSelectedDotModel = dot
                //当前中心点就是路径的起点
                mPath.moveTo(dot.cx,dot.cy)
                //记录当前点的值
                mPasswordBuilder.append(dot.num)
            }else{
                //自己内部就不要画
                if (lastSelectedDotModel != dot) {
                    //判断这条线是否已经画过了
                    val lineValue = lineValue(lastSelectedDotModel!!,dot)
                    if (!mSelectedLines.contains(lineValue)) {
                        //两点之间画一条线
                        mPath.lineTo(dot.cx, dot.cy)
                        lastSelectedDotModel = dot
                        mSelectedLines.add(lineValue)
                       addMoveLine(x,y)
                        //记录当前点的值
                        mPasswordBuilder.append(dot.num)
                    }
                }else{
                    addMoveLine(x,y)
                }
            }
            dot.state = DotState.Selected
            //点亮 -> 绘制一个圆
            invalidate()
        }else{
            if (lastSelectedDotModel != null) {
                //从上一个点和当前点连成一条线
                addMoveLine(x,y)
                invalidate()
            }
        }
    }
    private fun touchEnd(){
        //获取密码
        val password = mPasswordBuilder.toString()
        mBackupPath = Path(mPath)
        mBackupModels = ArrayList(mDotModels)
        //清空
        clear()
        mCallback?.let { it(this,password) } //数据回调出去
    }
    /**外部监听密码绘制结束的监听器*/
    fun addDrawFinishedListener(callback:(UnlockView,String)->Unit){
        mCallback = callback
    }

    private var canTouch = true
    /**显示错误状态*/
    fun showError(){
        canTouch = false
        //恢复
        mPath = mBackupPath?: Path()
        mDotModels = mBackupModels?: arrayListOf()
        mDotModels.forEach {
            if (it.state == DotState.Selected){
                it.state = DotState.Error
            }
        }
        mLinePaint.color = resources.getColor(R.color.red, null)
        invalidate()
        postDelayed({
            mLinePaint.color = resources.getColor(R.color.light_blue, null)
            mBackupPath = null
            mBackupModels = null
            canTouch = true
            clear()
        },500)
    }
    private fun clear(){
        //models
        mPasswordBuilder.clear()
        mMoveLinePath.reset()
        mPath.reset()
        mSelectedLines.clear()
        lastSelectedDotModel = null
        mDotModels.clear()
        invalidate()
    }

    /**确定拉伸线的路劲*/
    private fun addMoveLine(x:Float,y:Float){
        mMoveLinePath.reset()
        mMoveLinePath.moveTo(lastSelectedDotModel!!.cx, lastSelectedDotModel!!.cy)
        mMoveLinePath.lineTo(x,y)
    }

    /**两点之间是否有线*/
    private fun lineValue(first:DotModel, second:DotModel):Int{
        return Math.min(first.num,second.num) * 10 + Math.max(first.num,second.num)
    }

    /**是否在某一个圆点内部*/
    private fun isInDot(x: Float,y: Float): DotModel?{
        mDotModels.forEach {
            if (it.containsPoint(x,y)){
                return it
            }
        }
        return null
    }

    private fun squareSize() = Math.min(width,height)
}